package cn.org.xiaosheng.client.aspectJ;

import cn.org.xiaosheng.client.annotation.RpcClient;
import cn.org.xiaosheng.client.manager.RpcClientManager;
import cn.org.xiaosheng.core.message.RpcRequestMessage;
import cn.org.xiaosheng.core.protocol.SequenceIdGenerator;
import com.alibaba.nacos.api.exception.NacosException;
import com.google.gson.JsonObject;
import io.netty.util.concurrent.DefaultPromise;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.lang.reflect.Proxy;

/**
 * @RpcClient注解切面
 * @author XiaoSheng
 * @date 2024/8/22 下午2:31
 */
@Aspect
@Slf4j
@Component
public class RpcClientAspectJ {

    private RpcClientManager rpcClientManager;

    public RpcClientAspectJ(RpcClientManager rpcClientManager) {
        this.rpcClientManager = rpcClientManager;
    }

    /**
     * 切点
     * 注意：这里的路径最好写全路径 不写全有时会有错误
     *
     * 参数说明：
     * 使用@annotation时，所修饰的方法或是接口都会被拦截。
     * 使用execution时，指定你要切入的一个地方。
     */
//    @Pointcut("@annotation(cn.org.xiaosheng.client.annotation.RpcClient)")
//    public void pointCut() {
//
//    }

//    @Around("pointCut()")
    @Around("@annotation(rpc)")
    public Object around(ProceedingJoinPoint joinPoint, RpcClient rpc) {
        // 获取被拦截方法的签名信息
        Signature signature = joinPoint.getSignature();
        // 获取被拦截方法的实际目标对象
        Class target = joinPoint.getTarget().getClass();
        // 获取被拦截方法的参数列表
        Object[] args = joinPoint.getArgs();

        ClassLoader classLoader = target.getClassLoader();
        Class[] interfaces = target.getInterfaces();

        MethodSignature methodSignature = (MethodSignature) signature;
        String serverName;
        String methodName;
        Class returnType;
        // 获取方法上的RpcClient注解
        RpcClient rpcClient = methodSignature.getMethod().getAnnotation(RpcClient.class);
        if (rpcClient.serverName() != null && !"".equals(rpcClient.serverName())) {
            serverName = rpcClient.serverName();
        } else {
            serverName = target.getSimpleName();
        }

        if (rpcClient.methodName() != null && !"".equals(rpcClient.methodName())) {
            methodName = rpcClient.methodName();
        } else {
            methodName = signature.getName();
        }

        if (rpcClient.returnType() != null) {
            returnType = rpcClient.returnType();
        } else {
            returnType = methodSignature.getReturnType();
        }
        // 1. 将方法调用转换为 消息对象
        int sequenceId = SequenceIdGenerator.nextId();
        RpcRequestMessage msg = new RpcRequestMessage(
                    sequenceId,
                    serverName,
                    methodName,
                    returnType,
                    methodSignature.getParameterTypes(),
                    args
        );
        System.out.println(msg);
        DefaultPromise<Object> promise = new DefaultPromise<Object>(RpcClientManager.group.next());
        RpcClientManager.PROMISES.put(sequenceId, promise);

        try {
            // 3. 将消息对象发送出去
            rpcClientManager.sendRpcRequest(msg);
            // 4. 等待 promise 结果
            promise.await();
        } catch (InterruptedException | NacosException e) {
            throw new RuntimeException(e);
        }
        if(promise.isSuccess()) {
            // 调用正常, 最后得出结论, 在服务端将方法调用完成后, 服务端将方法调用结果通过消息传递给客户端
            System.out.println("客户端消息响应结果: " + promise.getNow().toString());
            return promise.getNow();
        } else {
            // 调用失败
            throw new RuntimeException(promise.cause());
        }
    }

}
